package xcmg.device.service.logistic;

import com.github.pagehelper.PageInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptDO;
import xcmg.device.dao.entity.logistic.LogisticNodeRecordDO;
import xcmg.device.dao.entity.logistic.LogisticWaybillDO;
import xcmg.device.dao.entity.logistic.LogisticWaybillDetailDO;
import xcmg.device.dao.entity.logistic.LogisticWaybillFeeDO;
import xcmg.device.dao.entity.logistic.LogisticWaybillFeeDetailDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesOutDO;
import xcmg.device.dao.mapper.CompanyDealerMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptMapper;
import xcmg.device.dao.mapper.logistic.LogisticNodeRecordMapper;
import xcmg.device.dao.mapper.logistic.LogisticWaybillDetailMapper;
import xcmg.device.dao.mapper.logistic.LogisticWaybillFeeDetailMapper;
import xcmg.device.dao.mapper.logistic.LogisticWaybillFeeMapper;
import xcmg.device.dao.mapper.logistic.LogisticWaybillMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesOutMapper;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.enums.LogisticNodeTypeEnum;
import xcmg.device.infra.enums.LogisticRecodeOperateTypeEnum;
import xcmg.device.infra.enums.LogisticWayBillFeeStatusEnum;
import xcmg.device.infra.enums.LogisticWayBillStatusEnum;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.crm.util.ActionResultUtil;
import xcmg.device.service.vo.delivery.ExpressTracesVO;
import xcmg.device.service.vo.logistic.BusinessOrderSelectedInfoVO;
import xcmg.device.service.vo.logistic.FeePageViewWaybillInfoVO;
import xcmg.device.service.vo.logistic.LogisticBillwayPrintVO;
import xcmg.device.service.vo.logistic.LogisticNodeRecordEnterVO;
import xcmg.device.service.vo.logistic.LogisticNodeRecordVO;
import xcmg.device.service.vo.logistic.LogisticStatusDisplayBoardVO;
import xcmg.device.service.vo.logistic.LogisticStatusListingWaybillVO;
import xcmg.device.service.vo.logistic.LogisticWayBilDeliveryConfirmVO;
import xcmg.device.service.vo.logistic.LogisticWayBillAuditVO;
import xcmg.device.service.vo.logistic.LogisticWayBillListQueryParamVO;
import xcmg.device.service.vo.logistic.LogisticWayBillListQueryResultVO;
import xcmg.device.service.vo.logistic.LogisticWayBillModifyVO;
import xcmg.device.service.vo.logistic.LogisticWayBillSaveVO;
import xcmg.device.service.vo.logistic.LogisticWayBillViewInfoVO;
import xcmg.device.service.vo.logistic.LogisticWayLinkBillDetailVO;
import xcmg.device.service.vo.logistic.LogisticWaybillArrivalConfirmVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeApprovalVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeAuditVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeListQueryParamVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeListingResultVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeePrintVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeSaveVO;
import xcmg.device.service.vo.logistic.LogisticWaybillFeeViewResponseVO;
import xcmg.device.service.vo.logistic.LogisticWaybillSelectResultVO;
import xcmg.device.service.vo.logistic.SelectBusinessBillResultVO;
import xcmg.device.service.vo.logistic.SelectBusinessBillsQueryParamVO;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.PageHelperPlus;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@Slf4j
public class LogisticWayBillService {
    @Autowired
    private DeliveryReceiptMapper deliveryReceiptMapper;
    @Autowired
    private ThreeGuaranteesOutMapper threeGuaranteesOutMapper;
    @Autowired
    private FastGenClient fastGenClient;
    @Autowired
    private GenDocumentService genDocumentService;
    @Autowired
    private CompanyDealerMapper companyDealerMapper;
    @Autowired
    private LogisticWaybillMapper logisticWaybillMapper;
    @Autowired
    private LogisticWaybillDetailMapper logisticWaybillDetailMapper;
    @Autowired
    private LogisticWaybillFeeMapper logisticWaybillFeeMapper;
    @Autowired
    private LogisticWaybillFeeDetailMapper logisticWaybillFeeDetailMapper;
    @Autowired
    private LogisticNodeRecordMapper logisticNodeRecordMapper;
//    @Autowired
//    private WDExpressClient wdExpressClient;

    /**
     * @Des 分页查询可以创建物流运单的发运交接单
     * @Date 2021/4/27 10:37
     * @Author wangzhaoyu
     * @Param [condition]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.SelectBusinessBillResultVO>
     */
    public PageCommonVO<SelectBusinessBillResultVO> receiptBusinessOrders(SearchCommonVO<SelectBusinessBillsQueryParamVO> condition) {
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SelectBusinessBillResultVO> selectBusinessBillResultVOS = deliveryReceiptMapper.list4LogisticWaybill(condition.getFilters());
        PageCommonVO result = new PageCommonVO();
        result.setPageInfo(new PageInfo(selectBusinessBillResultVOS));
        return result;
    }


    /**
     * @Des 分页查询可以创建物流运单的三包出库单
     * @Date 2021/4/27 10:38
     * @Author wangzhaoyu
     * @Param [condition]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.SelectBusinessBillResultVO>
     */
    public PageCommonVO<SelectBusinessBillResultVO> threeOutBusinessOrders(SearchCommonVO<SelectBusinessBillsQueryParamVO> condition) {
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SelectBusinessBillResultVO> selectBusinessBillResultVOS = threeGuaranteesOutMapper.list4LogisticWaybill(condition.getFilters());
        PageCommonVO<SelectBusinessBillResultVO> result = new PageCommonVO();
        result.setPageInfo(new PageInfo(selectBusinessBillResultVOS));
        return result;
    }

    /**
     * @Des 创建物流运单时选择了多个单据并确认后展示选择单据 的信息，表头带出第一个单据的客户信息，发运方式，承运商信息
     * 零件详情中展示单据中未被创建过物流运单的零件
     * @Date 2021/5/12 18:19
     * @Author wangzhaoyu
     * @Param [businessOrderNos]
     * @Return xcmg.device.service.vo.logistic.BusinessOrderSelectedInfoVO
     */
    public BusinessOrderSelectedInfoVO threeGuaranteesOutsSelectedInfo(String[] businessOrderNos,String orgId){
        BusinessOrderSelectedInfoVO result = new BusinessOrderSelectedInfoVO();
        if(ArrayUtils.isEmpty(businessOrderNos)){
            return result;
        }
        //查询第一个能查到的单据的信息放在表头
        ThreeGuaranteesOutDO guaranteesOutDO = null;
        for(int i = 0;i< businessOrderNos.length ;i++){
            guaranteesOutDO = threeGuaranteesOutMapper.logisticWayHeadInfo(businessOrderNos[i],orgId);
            if(guaranteesOutDO != null){
                break;
            }
        }
        //为查询到有效单据，直接返回空表头，空零件组
        if(guaranteesOutDO == null){
            return result;
        }
        BusinessOrderSelectedInfoVO.HeadInfo headInfo = new BusinessOrderSelectedInfoVO.HeadInfo();
        headInfo.setDealerOrgId(guaranteesOutDO.getPurCustomerId());
        headInfo.setDealerOrgName(guaranteesOutDO.getPurCustomerName());
        headInfo.setReceiverName(guaranteesOutDO.getReceiverName());
        headInfo.setReceiverAddress(guaranteesOutDO.getAddress());
        headInfo.setReceiverTel(guaranteesOutDO.getReceiverPhone());
        result.setHeadInfo(headInfo);
        List<BusinessOrderSelectedInfoVO.Materials> materials = threeGuaranteesOutMapper.listNotBeLogisticWayMaterials(Arrays.asList(businessOrderNos));
        result.getMaterialses().addAll(materials);
        return result;
    }

    /**
     * @Des 创建物流运单时选择了多个单据并确认后展示选择单据 的信息，表头带出第一个单据的客户信息，发运方式，承运商信息
     * 零件详情中展示单据中未被创建过物流运单的零件
     * @Date 2021/5/12 17:28
     * @Author wangzhaoyu
     * @Param []
     * @Return xcmg.device.service.vo.logistic.BusinessOrderSelectedInfoVO
     */
    public BusinessOrderSelectedInfoVO deliveryReceiptsSelectedInfo(String[] businessOrderNos){
        BusinessOrderSelectedInfoVO result = new BusinessOrderSelectedInfoVO();
        if(ArrayUtils.isEmpty(businessOrderNos)){
            return result;
        }
        //查询第一个能查到的单据的信息放在表头
        DeliveryReceiptDO receiptDO = null;
        for(int i = 0;i< businessOrderNos.length ;i++){
            receiptDO = deliveryReceiptMapper.itemByNo(businessOrderNos[i]);
            if(receiptDO != null){
                break;
            }
        }
        //为查询到有效单据，直接返回空表头，空零件组
        if(receiptDO == null){
            return result;
        }
        BusinessOrderSelectedInfoVO.HeadInfo headInfo = new BusinessOrderSelectedInfoVO.HeadInfo();
        headInfo.setCarrierOrgId(receiptDO.getCarrierOrgId());
        headInfo.setCarrierOrgName(receiptDO.getCarrierOrgName());
        headInfo.setDealerOrgId(receiptDO.getDealerOrgId());
        headInfo.setDealerOrgName(receiptDO.getDealerOrgName());
        headInfo.setShippingMethodId(receiptDO.getShippingMethodId());
        headInfo.setShippingMethod(receiptDO.getShippingMethod());
        headInfo.setReceiverTel(receiptDO.getReceiverTel());
        headInfo.setReceiverName(receiptDO.getReceiverName());
        headInfo.setReceiverAddress(receiptDO.getReceiverAddress());
        headInfo.setDeliveryTime(receiptDO.getDeliveryDate());
        //查询未被创建物流运单的零件信息
        List<BusinessOrderSelectedInfoVO.Materials> materials = deliveryReceiptMapper.listNotBeLogisticWayMaterials(Arrays.asList(businessOrderNos));
        result.getMaterialses().addAll(materials);
        result.setHeadInfo(headInfo);
        return result;
    }

    /**
     * @Des 新增物流运单
     * @Date 2021/5/13 11:05
     * @Author wangzhaoyu
     * @Param [logisticWayBillSaveVO, orgId, operateType:0保存，1提交]
     * @Return void
     */
    @Transactional
    public void addLogistic(LogisticWayBillSaveVO logisticWayBillSaveVO,String orgId,String userId,String userName,Integer operateType) throws Exception {
        LogisticWayBillSaveVO.HeadInfo headInfo = logisticWayBillSaveVO.getHeadInfo();
        List<LogisticWayBillSaveVO.Materials> materialses = logisticWayBillSaveVO.getMaterialses();
        if(headInfo == null || CollectionUtils.isEmpty(materialses)){
            throw new Exception("至少选择一个单据及零件");
        }
        String businessType = headInfo.getBusinessType();
        if(StringUtils.isEmpty(businessType)){
            log.error("缺少必要参数businessType");
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        //拼接需要保存的主表信息
        LogisticWaybillDO logisticWaybillDO = assembleLogisticWaybillInsert(logisticWayBillSaveVO,orgId,userId,userName,operateType);
        logisticWaybillMapper.insertSelective(logisticWaybillDO);
        //拼接需要保存的零件详情表信息
        List<LogisticWaybillDetailDO> logisticWaybillDetails = assembleLogisticWaybillDetailInsert(logisticWayBillSaveVO,logisticWaybillDO);
        logisticWaybillDetailMapper.batchInsert(logisticWaybillDetails);
    }

    /**
     * @Des 拼接物流运单主表保存信息
     * @Date 2021/5/13 11:06
     * @Author wangzhaoyu
     * @Param [logisticWayBillSaveVO, orgId, operateType]
     * @Return xcmg.device.dao.entity.logistic.LogisticWaybillDO
     */
    private LogisticWaybillDO assembleLogisticWaybillInsert(LogisticWayBillSaveVO logisticWayBillSaveVO,String orgId,String userId,String userName ,Integer operateType) throws Exception {
        LogisticWayBillSaveVO.HeadInfo headInfo = logisticWayBillSaveVO.getHeadInfo();
        if(headInfo == null){
            throw new Exception("至少选择一个单据");
        }
        ActionResult<String> idReslt = fastGenClient.textGuid();
        if (idReslt == null || idReslt.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        String wayBillNo = genDocumentService.genDocumentNo(BillDesc.LogisticWaybill, orgId);
        LogisticWaybillDO result = new LogisticWaybillDO();
        result.setId(idReslt.getValue());
        result.setWayBillNo(wayBillNo);
        result.setOrgId(orgId);
        String dealerOrgId = headInfo.getDealerOrgId();
        if(StringUtils.isEmpty(dealerOrgId)){
            throw new Exception("请选择客户");
        }
        //通过前端传过来的dealerOrgId到客户表查询，使用company_dealer表的id,dealer_org_id,plat_org_id 同时匹配，取第一条有效记录
        CompanyDealerDO effiectiveDealer = getEffiectiveDealer(dealerOrgId, orgId);
        if(effiectiveDealer == null){
            throw new Exception("未查询到有效客户");
        }
        result.setDealerOrgId(effiectiveDealer.getDealerOrgId());
        result.setDealerOrgName(effiectiveDealer.getCompanyName());
        Integer status;
        switch (operateType){
            case 0 : status = LogisticWayBillStatusEnum.SAVE.getStatus() ;break;
            case 1 : status = LogisticWayBillStatusEnum.SUBMIT.getStatus() ;break;
            default : status = null;
        }
        result.setStatus(status);
        result.setReceiverName(headInfo.getReceiverName());
        result.setReceiverTel(headInfo.getReceiverTel());
        result.setReceiverAddress(headInfo.getReceiverAddress());
        result.setDeliveryTime(headInfo.getDeliveryTime());
        result.setUnitPrice(headInfo.getUnitPrice());
        result.setKilometers(headInfo.getKilometers());
        result.setGpsNo(headInfo.getGpsNo());
        result.setInitinalCarriage(headInfo.getInitinalCarriage());
        result.setFinalCarriage(headInfo.getInitinalCarriage());
        result.setBusinessType(headInfo.getBusinessType());
        result.setShippingMethodId(headInfo.getShippingMethodId());
        result.setShippingMethod(headInfo.getShippingMethod());
        result.setCarrierOrgId(headInfo.getCarrierOrgId());
        result.setCarrierOrgName(headInfo.getCarrierOrgName());
        result.setAmount(headInfo.getAmount());
        result.setBoxTrunkFee(headInfo.getBoxTrunkFee());
        result.setPackagingFee(headInfo.getPackagingFee());
        result.setLogisticFee(headInfo.getLogisticFee());
        result.setHandlingCost(headInfo.getHandlingCost());
        result.setExpressCode(headInfo.getExpressCode());
        result.setFreightNo(headInfo.getFreightNo());
        result.setModel(headInfo.getModel());
        result.setRemark(headInfo.getRemark());
        result.setCreateDate(new Date());
        result.setCerateUserId(userId);
        result.setCreateUserName(userName);
        result.setLogisticStatus(LogisticNodeTypeEnum.INIT.getType());
        return result;
    }

    /**
     * @Des 通过前端传过来的dealerOrgId到客户表查询，使用company_dealer表的id,dealer_org_id,plat_org_id 同时匹配，取第一条有效记录
     * @Date 2021/5/13 10:57
     * @Author wangzhaoyu
     * @Param [dealerOrgId, orgId]
     * @Return xcmg.device.dao.entity.company.CompanyDealerDO
     */
    private CompanyDealerDO getEffiectiveDealer(String dealerOrgId,String orgId){
        List<CompanyDealerDO> companyDealers = companyDealerMapper.selectByDealerOrgId(dealerOrgId, orgId);
        if(CollectionUtils.isEmpty(companyDealers)){
            return null;
        }
        for(CompanyDealerDO dealer : companyDealers){
            Boolean isDel = dealer.getIsDel();
            if(isDel != null && isDel){
                continue;
            }
            return dealer;
        }
        //如果都是已删除的，直接返回被删除的客户中，最新创建的1条记录
        return companyDealers.get(0);
    }

    private List<LogisticWaybillDetailDO> assembleLogisticWaybillDetailInsert(LogisticWayBillSaveVO logisticWayBillSaveVO,LogisticWaybillDO logisticWaybillDO) throws Exception {
        List<LogisticWayBillSaveVO.Materials> materialses = logisticWayBillSaveVO.getMaterialses();
        if(CollectionUtils.isEmpty(materialses)){
            throw new Exception("至少选择一个零件");
        }
        //遍历拼接
        List<LogisticWaybillDetailDO> result = new LinkedList<>();
        for(LogisticWayBillSaveVO.Materials materials : materialses){
            LogisticWaybillDetailDO detailInsert = new LogisticWaybillDetailDO();
            ActionResult<String> idReslt = fastGenClient.textGuid();
            if (idReslt == null || idReslt.getCode() != 0) {
                throw new Exception("生成唯一标识失败");
            }
            detailInsert.setId(idReslt.getValue());
            detailInsert.setAmount(materials.getAmount());
            detailInsert.setBusinessOrderNo(materials.getBusinessOrderNo());
            detailInsert.setMaterialsNo(materials.getMaterialsNo());
            detailInsert.setWayBillId(logisticWaybillDO.getId());
            detailInsert.setMaterialsDesc(materials.getMaterialsDesc());
            detailInsert.setUnit(materials.getUnit());
            result.add(detailInsert);
        }
        return result;
    }

    /**
     * @Des 编辑物流运单
     * @Date 2021/5/13 17:57
     * @Author wangzhaoyu
     * @Param [logisticWayBillSaveVO, orgId, userId, userName, operateType]
     * @Return void
     */
    @Transactional
    public void updateLogistic(LogisticWayBillSaveVO logisticWayBillSaveVO,int operateType) throws Exception {
        LogisticWayBillSaveVO.HeadInfo headInfo = logisticWayBillSaveVO.getHeadInfo();
        String id = headInfo.getId();
        LogisticWaybillDO oldLogisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        LogisticWaybillDO newLogisticWaybillDO = assembleLogisticWaybillUpdate(oldLogisticWaybillDO, logisticWayBillSaveVO, operateType);
        logisticWaybillMapper.updateByPrimaryKeySelective(newLogisticWaybillDO);
        //更新详情信息，包括新增/覆盖/删除
        List<LogisticWaybillDetailDO> logisticWaybillDetails = assembleLogisticWaybillDetailUpdate(logisticWayBillSaveVO, newLogisticWaybillDO);
        List<LogisticWaybillDetailDO> oldLogisticWaybillDetails = logisticWaybillDetailMapper.selectByWayBillId(newLogisticWaybillDO.getId());
        //筛选出需要新增的/更新的/删除的
        List<LogisticWaybillDetailDO> needInserts = new LinkedList<>();
        for(LogisticWaybillDetailDO requestDetail : logisticWaybillDetails){
            if(oldLogisticWaybillDetails.contains(requestDetail)){
                //如果老的里面已经存在当前遍历到的记录，把该记录从老集合中中删除掉，最后老集合列表中剩余的就是本次请求中没有的，说明本次操作进行了删除单据的操作
                oldLogisticWaybillDetails.remove(requestDetail);
            }else{
                needInserts.add(requestDetail);
            }
        }
        if(!CollectionUtils.isEmpty(oldLogisticWaybillDetails)){
            //删除需要删除的
            logisticWaybillDetailMapper.deleteBatch(oldLogisticWaybillDetails);
        }
        //插入新增的
        for(LogisticWaybillDetailDO deatilInsert : needInserts){
            ActionResult<String> idResult = fastGenClient.textGuid();
            if (idResult == null || idResult.getCode() != 0) {
                throw new Exception("生成唯一标识失败");
            }
            String insertId = idResult.getValue();
            deatilInsert.setId(insertId);
        }
        if(!CollectionUtils.isEmpty(needInserts)){
            logisticWaybillDetailMapper.batchInsert(needInserts);
        }
    }


    /**
     * @Des 拼接物流运单主表保存信息
     * @Date 2021/5/13 11:06
     * @Author wangzhaoyu
     * @Param [logisticWayBillSaveVO, orgId, operateType]
     * @Return xcmg.device.dao.entity.logistic.LogisticWaybillDO
     */
    private LogisticWaybillDO assembleLogisticWaybillUpdate(LogisticWaybillDO oldLogisticWaybillDO,LogisticWayBillSaveVO logisticWayBillSaveVO,Integer operateType) throws Exception {
        LogisticWayBillSaveVO.HeadInfo headInfo = logisticWayBillSaveVO.getHeadInfo();
        if(headInfo == null){
            throw new Exception("至少选择一个单据");
        }
        String dealerOrgId = headInfo.getDealerOrgId();
        if(StringUtils.isEmpty(dealerOrgId)){
            throw new Exception("请选择客户");
        }
        String orgId = oldLogisticWaybillDO.getOrgId();
        //通过前端传过来的dealerOrgId到客户表查询，使用company_dealer表的id,dealer_org_id,plat_org_id 同时匹配，取第一条有效记录
        CompanyDealerDO effiectiveDealer = getEffiectiveDealer(dealerOrgId, orgId);
        if(effiectiveDealer == null){
            throw new Exception("未查询到有效客户");
        }
        oldLogisticWaybillDO.setDealerOrgId(effiectiveDealer.getDealerOrgId());
        oldLogisticWaybillDO.setDealerOrgName(effiectiveDealer.getCompanyName());
        Integer status;
        switch (operateType){
            case 0 : status = LogisticWayBillStatusEnum.SAVE.getStatus() ;break;
            case 1 : status = LogisticWayBillStatusEnum.SUBMIT.getStatus() ;break;
            default : status = null;
        }
        oldLogisticWaybillDO.setStatus(status);
        oldLogisticWaybillDO.setReceiverName(headInfo.getReceiverName());
        oldLogisticWaybillDO.setReceiverTel(headInfo.getReceiverTel());
        oldLogisticWaybillDO.setReceiverAddress(headInfo.getReceiverAddress());
        oldLogisticWaybillDO.setDeliveryTime(headInfo.getDeliveryTime());
        oldLogisticWaybillDO.setUnitPrice(headInfo.getUnitPrice());
        oldLogisticWaybillDO.setKilometers(headInfo.getKilometers());
        oldLogisticWaybillDO.setGpsNo(headInfo.getGpsNo());
        oldLogisticWaybillDO.setInitinalCarriage(headInfo.getInitinalCarriage());
        oldLogisticWaybillDO.setBusinessType(headInfo.getBusinessType());
        oldLogisticWaybillDO.setShippingMethodId(headInfo.getShippingMethodId());
        oldLogisticWaybillDO.setShippingMethod(headInfo.getShippingMethod());
        oldLogisticWaybillDO.setCarrierOrgId(headInfo.getCarrierOrgId());
        oldLogisticWaybillDO.setCarrierOrgName(headInfo.getCarrierOrgName());
        oldLogisticWaybillDO.setAmount(headInfo.getAmount());
        oldLogisticWaybillDO.setBoxTrunkFee(headInfo.getBoxTrunkFee());
        oldLogisticWaybillDO.setPackagingFee(headInfo.getPackagingFee());
        oldLogisticWaybillDO.setLogisticFee(headInfo.getLogisticFee());
        oldLogisticWaybillDO.setHandlingCost(headInfo.getHandlingCost());
        oldLogisticWaybillDO.setExpressCode(headInfo.getExpressCode());
        oldLogisticWaybillDO.setFreightNo(headInfo.getFreightNo());
        oldLogisticWaybillDO.setModel(headInfo.getModel());
        oldLogisticWaybillDO.setRemark(headInfo.getRemark());
        return oldLogisticWaybillDO;
    }

    private List<LogisticWaybillDetailDO> assembleLogisticWaybillDetailUpdate(LogisticWayBillSaveVO logisticWayBillSaveVO,LogisticWaybillDO newLogisticWaybillDO) throws Exception {
        List<LogisticWayBillSaveVO.Materials> materialses = logisticWayBillSaveVO.getMaterialses();
        if(CollectionUtils.isEmpty(materialses)){
            throw new Exception("至少选择一个零件");
        }
        //判断同一个业务单据的同一个零件不能重复添加,使用单据号+零件号作为key,校验重复
        Set<String> dulCheck = new HashSet<>();
        //遍历拼接
        List<LogisticWaybillDetailDO> result = new LinkedList<>();
        for(LogisticWayBillSaveVO.Materials materials : materialses){
            String businessOrderNo = materials.getBusinessOrderNo();
            String materialsNo = materials.getMaterialsNo();
            LogisticWaybillDetailDO detailUpdate = new LogisticWaybillDetailDO();
            detailUpdate.setId(materials.getId());
            detailUpdate.setWayBillId(materials.getWayBillId());
            detailUpdate.setAmount(materials.getAmount());
            detailUpdate.setBusinessOrderNo(businessOrderNo);
            detailUpdate.setMaterialsNo(materialsNo);
            detailUpdate.setUnit(materials.getUnit());
            detailUpdate.setWayBillId(newLogisticWaybillDO.getId());
            detailUpdate.setMaterialsDesc(materials.getMaterialsDesc());
            String dulCheckKey = businessOrderNo + materialsNo;
            if(dulCheck.contains(dulCheckKey)){
                String errorMsg = "单据"+businessOrderNo + ",零件:"+materialsNo+"重复添加";
                throw new Exception(errorMsg);
            }
            result.add(detailUpdate);
        }
        return result;
    }

    /**
     * @Des 编辑操作时获取物流运单原信息
     * @Date 2021/5/14 9:00
     * @Author wangzhaoyu
     * @Param [id]
     * @Return void
     */
    public LogisticWayBillSaveVO editViewInfo(String id) {
        //获取表头信息
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        //获取表体详情信息
        List<LogisticWaybillDetailDO> logisticWaybillDetails = logisticWaybillDetailMapper.selectByWayBillId(id);
        LogisticWayBillSaveVO result = new LogisticWayBillSaveVO();
        LogisticWayBillSaveVO.HeadInfo headInfoResult = assembleViewHeadInfo(logisticWaybillDO);
        result.setHeadInfo(headInfoResult);
        List<LogisticWayBillSaveVO.Materials> materialsResult = assembleEditViewDetail(logisticWaybillDetails);
        result.setMaterialses(materialsResult);
        return result;
    }

    /**
     * @Des 编辑时查询原物流信息，表头返回详情信息
     * @Date 2021/5/14 9:12
     * @Author wangzhaoyu
     * @Param [logisticWaybillDetails]
     * @Return java.util.List<xcmg.device.service.vo.logistic.LogisticWayBillSaveVO.Materials>
     */
    private List<LogisticWayBillSaveVO.Materials> assembleEditViewDetail(List<LogisticWaybillDetailDO> logisticWaybillDetails) {
        if(CollectionUtils.isEmpty(logisticWaybillDetails)){
            return Collections.EMPTY_LIST;
        }
        List<LogisticWayBillSaveVO.Materials> result = new LinkedList<>();
        for(LogisticWaybillDetailDO detail : logisticWaybillDetails){
            LogisticWayBillSaveVO.Materials materials = new LogisticWayBillSaveVO.Materials();
            materials.setId(detail.getId());
            materials.setWayBillId(detail.getWayBillId());
            materials.setAmount(detail.getAmount());
            materials.setBusinessOrderNo(detail.getBusinessOrderNo());
            materials.setMaterialsDesc(detail.getMaterialsDesc());
            materials.setMaterialsNo(detail.getMaterialsNo());
            materials.setUnit(detail.getUnit());
            result.add(materials);
        }
        return result;
    }

    /**
     * @Des 编辑时查询原物流信息，表头返回实体拼接
     * @Date 2021/5/14 9:09
     * @Author wangzhaoyu
     * @Param [logisticWaybillDO, wayBillSaveVO]
     * @Return void
     */
    private LogisticWayBillSaveVO.HeadInfo assembleViewHeadInfo(LogisticWaybillDO logisticWaybillDO){
        LogisticWayBillSaveVO.HeadInfo result = new LogisticWayBillSaveVO.HeadInfo();
        if(logisticWaybillDO == null){
            return result;
        }
        result.setId(logisticWaybillDO.getId());
        result.setWayBillNo(logisticWaybillDO.getWayBillNo());
        result.setReceiverTel(logisticWaybillDO.getReceiverTel());
        result.setReceiverName(logisticWaybillDO.getReceiverName());
        result.setReceiverAddress(logisticWaybillDO.getReceiverAddress());
        result.setDeliveryTime(logisticWaybillDO.getDeliveryTime());
        result.setAfterModifyCarriage(logisticWaybillDO.getAfterModifyCarriage());
        result.setAmount(logisticWaybillDO.getAmount());
        result.setBoxTrunkFee(logisticWaybillDO.getBoxTrunkFee());
        result.setBusinessType(logisticWaybillDO.getBusinessType());
        result.setCarrierOrgId(logisticWaybillDO.getCarrierOrgId());
        result.setCarrierOrgName(logisticWaybillDO.getCarrierOrgName());
        result.setDealerOrgId(logisticWaybillDO.getDealerOrgId());
        result.setDealerOrgName(logisticWaybillDO.getDealerOrgName());
        result.setExpressCode(logisticWaybillDO.getExpressCode());
        result.setFreightNo(logisticWaybillDO.getFreightNo());
        result.setGpsNo(logisticWaybillDO.getGpsNo());
        result.setHandlingCost(logisticWaybillDO.getHandlingCost());
        result.setInitinalCarriage(logisticWaybillDO.getInitinalCarriage());
        result.setKilometers(logisticWaybillDO.getKilometers());
        result.setLogisticFee(logisticWaybillDO.getLogisticFee());
        result.setModel(logisticWaybillDO.getModel());
        result.setPackagingFee(logisticWaybillDO.getPackagingFee());
        result.setRemark(logisticWaybillDO.getRemark());
        result.setShippingMethod(logisticWaybillDO.getShippingMethod());
        result.setShippingMethodId(logisticWaybillDO.getShippingMethodId());
        result.setUnitPrice(logisticWaybillDO.getUnitPrice());
        return result;
    }

    /**
     * @Des 查看单据详情信息
     * @Date 2021/5/14 14:40
     * @Author wangzhaoyu
     * @Param [id]
     * @Return xcmg.device.service.vo.logistic.LogisticWayBillSaveVO
     */
    public LogisticWayBillViewInfoVO viewInfo(String id) {
        //获取表头信息
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        //获取表体详情信息
        LogisticWayBillViewInfoVO result = new LogisticWayBillViewInfoVO();
        LogisticWayBillSaveVO.HeadInfo headInfoResult = assembleViewHeadInfo(logisticWaybillDO);
        result.setHeadInfo(headInfoResult);
        //关联单据信息
        assembleLinkBills(logisticWaybillDO.getBusinessType(),result,logisticWaybillDO.getId());
        return result;
    }

    /**
     * @Des 拼接关联单据及关联单据详情信息
     * @Date 2021/5/14 14:45
     * @Author wangzhaoyu
     * @Param [businessType, result, logisticWaybillDetails]
     * @Return void
     */
    private void assembleLinkBills(String businessType, LogisticWayBillViewInfoVO result, String wayBillId){
        //不是发运交接单也不是三包出库单则直接拼接空集
        if(StringUtils.isEmpty(businessType)
                || (!businessType.equals(BillDesc.DeliveryReceiptNo.getDesc()) && (!businessType.equals(BillDesc.ThreeOut.getDesc())))){
            return ;
        }
        List<LogisticWayLinkBillDetailVO> logisticsWayLinkBillDetails;
        //判断如果是发运交接单则通过与发运交接单关联获取关联单据信息
        if(businessType.equals(BillDesc.DeliveryReceiptNo.getDesc())){
            logisticsWayLinkBillDetails = logisticWaybillDetailMapper.deliveryReceiptTypeLinkDetails(wayBillId);
        }else if(businessType.equals(BillDesc.ThreeOut.getDesc())){
            //如果是三包出库单则通过与三包出库单关联获取关联单据信息
            logisticsWayLinkBillDetails = logisticWaybillDetailMapper.threeOutTypeLinkDetails(wayBillId);
        }else{
            return ;
        }
        //拼接关联单据
        List<LogisticWayBillViewInfoVO.LinkBill> linkBills = new LinkedList<>();
        //用于去重关联单据
        Map<String, LogisticWayLinkBillDetailVO> logisticsWayLinkBillDetailMap = new HashMap<>();
        for(LogisticWayLinkBillDetailVO linkBillDetail : logisticsWayLinkBillDetails){
            String businessOrder = linkBillDetail.getBusinessOrder();
            logisticsWayLinkBillDetailMap.put(businessOrder,linkBillDetail);
        }
        Set<Map.Entry<String, LogisticWayLinkBillDetailVO>> linkBillDetailEntry = logisticsWayLinkBillDetailMap.entrySet();
        for(Map.Entry<String, LogisticWayLinkBillDetailVO> linkBillDetail : linkBillDetailEntry){
            LogisticWayLinkBillDetailVO value = linkBillDetail.getValue();
            String businessOrder = value.getBusinessOrder();
            String saleNo = value.getSaleNo();
            String purchaseNo = value.getPurchaseNo();
            String remark = value.getRemark();
            LogisticWayBillViewInfoVO.LinkBill linkBill = new LogisticWayBillViewInfoVO.LinkBill();
            linkBill.setBusinessOrder(businessOrder);
            linkBill.setSaleBillNo(saleNo);
            linkBill.setPurchaseNo(purchaseNo);
            linkBill.setRemark(remark);
            linkBills.add(linkBill);
        }
        result.setLinkBills(linkBills);

        //拼接关联单据详情
        List<LogisticWayBillViewInfoVO.LinkBillDetail> linkBillDetails = new LinkedList<>();
        for(LogisticWayLinkBillDetailVO linkBillDetail : logisticsWayLinkBillDetails){
            BigDecimal amount = linkBillDetail.getAmount();
            String businessOrder = linkBillDetail.getBusinessOrder();
            String materailsNo = linkBillDetail.getMaterailsNo();
            String materialsDesc = linkBillDetail.getMaterialsDesc();
            String unit = linkBillDetail.getUnit();
            LogisticWayBillViewInfoVO.LinkBillDetail linkDetail = new LogisticWayBillViewInfoVO.LinkBillDetail();
            linkDetail.setAmount(amount);
            linkDetail.setBusinessOrder(businessOrder);
            linkDetail.setMaterailsNo(materailsNo);
            linkDetail.setMaterialsDesc(materialsDesc);
            linkDetail.setUnit(unit);
            linkBillDetails.add(linkDetail);
        }
        result.setLinkBillDetails(linkBillDetails);
    }

    /**
     * @Des 物流运单列表查询
     * @Date 2021/5/18 10:15
     * @Author wangzhaoyu
     * @Param [orgId, condition]
     * @Return void
     */
    public PageCommonVO<LogisticWayBillListQueryResultVO> listingLogisticWayBills(String orgId, SearchCommonVO<LogisticWayBillListQueryParamVO> condition) {
        LogisticWayBillListQueryParamVO filters = condition.getFilters();
        Integer pageNum = condition.getPageNum();
        Integer pageSize = condition.getPageSize();
        PageHelperPlus.startPage(pageNum, pageSize);
        List<LogisticWaybillDO> logisticWayBills = logisticWaybillMapper.selectByListFilter(orgId,filters);
        List<LogisticWayBillListQueryResultVO> logisticWayBillListQueryResults = listQueryResultAssemble(logisticWayBills);
        PageCommonVO result = new PageCommonVO();
        result.setPageInfo(new PageInfo(logisticWayBills));
        result.setPageInfoList(logisticWayBillListQueryResults);
        return result;
    }

    private List<LogisticWayBillListQueryResultVO> listQueryResultAssemble(List<LogisticWaybillDO> logisticWayBills){
        List<LogisticWayBillListQueryResultVO> resultList = new ArrayList<>();
        for(LogisticWaybillDO logisticWaybillDO : logisticWayBills){
            LogisticWayBillListQueryResultVO queryResult = new LogisticWayBillListQueryResultVO();
            queryResult.setAfterModifyCarriage(logisticWaybillDO.getAfterModifyCarriage());
            queryResult.setAuditDate(logisticWaybillDO.getAuditDate());
            queryResult.setAuditRemark(logisticWaybillDO.getAuditRemark());
            queryResult.setAuditUserName(logisticWaybillDO.getAuditUserName());
            queryResult.setBusinessType(logisticWaybillDO.getBusinessType());
            queryResult.setCarrierOrgId(logisticWaybillDO.getCarrierOrgId());
            queryResult.setCarrierOrgName(logisticWaybillDO.getCarrierOrgName());
            queryResult.setCreateDate(logisticWaybillDO.getCreateDate());
            queryResult.setCreateUserName(logisticWaybillDO.getCreateUserName());
            queryResult.setDealerOrgId(logisticWaybillDO.getDealerOrgId());
            queryResult.setDealerOrgName(logisticWaybillDO.getDealerOrgName());
            queryResult.setDeliveryStatus(logisticWaybillDO.getDeliveryStatus());
            queryResult.setFinalCarriage(logisticWaybillDO.getFinalCarriage());
            queryResult.setId(logisticWaybillDO.getId());
            queryResult.setInitinalCarriage(logisticWaybillDO.getFinalCarriage());
            queryResult.setRemark(logisticWaybillDO.getRemark());
            queryResult.setShippingMethod(logisticWaybillDO.getShippingMethod());
            queryResult.setShippingMethodId(logisticWaybillDO.getShippingMethodId());
            queryResult.setStatus(logisticWaybillDO.getStatus());
            queryResult.setWayBillNo(logisticWaybillDO.getWayBillNo());
            resultList.add(queryResult);
        }
        return resultList;
    }

    public LogisticWayBillModifyVO modifyViewVO(String id) {
        if(StringUtils.isEmpty(id)){
            return null;
        }
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        if(logisticWaybillDO == null){
            return null;
        }
        LogisticWayBillModifyVO result = new LogisticWayBillModifyVO();
        result.setId(id);
        result.setWayBillNo(logisticWaybillDO.getWayBillNo());
        result.setDealerOrgName(logisticWaybillDO.getDealerOrgName());
        result.setModel(logisticWaybillDO.getModel());
        result.setKilometers(logisticWaybillDO.getKilometers());
        result.setGpsNo(logisticWaybillDO.getGpsNo());
        result.setInitinalCarriage(logisticWaybillDO.getInitinalCarriage());
        result.setAfterModifyCarriage(logisticWaybillDO.getAfterModifyCarriage());
        return result;
    }

    /**
     * @Des 物流运单变更
     * @Date 2021/5/18 16:26
     * @Author wangzhaoyu
     * @Param [modifyParam
     * operate : 0 : 保存 ， 1： 提交]
     * @Return void
     */
    public void modify(LogisticWayBillModifyVO modifyParam, int operate) throws Exception {
        String id = modifyParam.getId();
        if(StringUtils.isEmpty(id)){
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        if(logisticWaybillDO == null){
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        modifyParamCheck(modifyParam);
        //变更操作是修改单据的车型，公里数，GPS里程单，变更后费用
        logisticWaybillDO.setModel(modifyParam.getModel());
        logisticWaybillDO.setKilometers(modifyParam.getKilometers());
        logisticWaybillDO.setGpsNo(modifyParam.getGpsNo());
        logisticWaybillDO.setAfterModifyCarriage(modifyParam.getAfterModifyCarriage());
        logisticWaybillDO.setFinalCarriage(modifyParam.getAfterModifyCarriage());
        logisticWaybillDO.setModifyReason(modifyParam.getModifyReason());
        if(operate == 1){
            logisticWaybillDO.setStatus(LogisticWayBillStatusEnum.SUBMIT.getStatus());
        }else if(operate == 0){
            logisticWaybillDO.setStatus(LogisticWayBillStatusEnum.SAVE.getStatus());
        }
        int updateResult = logisticWaybillMapper.updateByPrimaryKeySelective(logisticWaybillDO);
        if(updateResult <= 0){
            throw new Exception(ErrorCode.Failure.getDesc());
        }
    }

    private void modifyParamCheck(LogisticWayBillModifyVO modifyParam) throws Exception {
        String gpsNo = modifyParam.getGpsNo();
        BigDecimal afterModifyCarriage = modifyParam.getAfterModifyCarriage();
        String modifyReason = modifyParam.getModifyReason();
        if(StringUtils.isEmpty(gpsNo)){
            throw new Exception("GPS里程单必填");
        }
        if(StringUtils.isEmpty(modifyReason)){
            throw new Exception("变更原因必填");
        }
        if(afterModifyCarriage == null){
            throw new Exception("变更后费用必填");
        }
    }

    /**
     * @Des 删除物流运单
     * @Date 2021/5/18 18:04
     * @Author wangzhaoyu
     * @Param [id]
     * @Return void
     */
    public void remove(String id) throws Exception {
        if(StringUtils.isEmpty(id)){
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        int removeResult = logisticWaybillMapper.remove(id);
    }

    /**
     * @Des 物流运单审核
     * @Date 2021/5/18 19:19
     * @Author wangzhaoyu
     * @Param [audit, pass ： true=通过，false=拒绝]
     * @Return void
     */
    public void audit(LogisticWayBillAuditVO audit,String auditUserId,String auditUserName, boolean pass) throws Exception {
        String id = audit.getId();
        String auditRemark = audit.getAuditRemark();
        if(StringUtils.isEmpty(id)){
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        if(StringUtils.isEmpty(auditRemark)){
            throw new Exception("审核意见必填");
        }
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        Integer status = logisticWaybillDO.getStatus();
        if(status == null || status.compareTo(LogisticWayBillStatusEnum.SUBMIT.getStatus())!= 0){
            throw new Exception("单据不是提交状态，不允许审核");
        }
        logisticWaybillDO.setAuditDate(new Date());
        logisticWaybillDO.setAuditUserId(auditUserId);
        logisticWaybillDO.setAuditUserName(auditUserName);
        logisticWaybillDO.setAuditRemark(auditRemark);
        if(pass){
            logisticWaybillDO.setStatus(LogisticWayBillStatusEnum.AUDIT_PASS.getStatus());
        }else{
            logisticWaybillDO.setStatus(LogisticWayBillStatusEnum.AUDIT_REJECT.getStatus());
        }
        logisticWaybillMapper.updateByPrimaryKeySelective(logisticWaybillDO);
    }

    /**
     * @Des 确认发货
     * @Date 2021/5/18 19:58
     * @Author wangzhaoyu
     * @Param [confirmParam]
     * @Return void
     */
    @Transactional
    public void deliveryConfirm(LogisticWayBilDeliveryConfirmVO confirmParam,String deliveryUserId,String deliveryUserName) throws Exception {
        String id = confirmParam.getId();
        if (StringUtils.isEmpty(id)) {
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        Date expectArrivalTime = confirmParam.getExpectArrivalTime();
        if (expectArrivalTime == null) {
            throw new Exception("预计到货时间为必填参数");
        }
        LogisticWaybillDO waybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        if(waybillDO == null){
            throw new Exception("未查询到物流运单记录");
        }
        //插入物流信息
        LogisticNodeRecordDO logisticNodeRecordDO = assembleDeliveryLogisticRecordSave(id, deliveryUserId, deliveryUserName);
        logisticNodeRecordMapper.insertSelective(logisticNodeRecordDO);
        //更新单据的确认发货信息
        LogisticWaybillDO confirmWayBill = new LogisticWaybillDO();
        confirmWayBill.setId(id);
        confirmWayBill.setExpectArrivalTime(expectArrivalTime);
        confirmWayBill.setDeliveryStatus(1);
        confirmWayBill.setDeliveryUserId(deliveryUserId);
        confirmWayBill.setDeliveryUserName(deliveryUserName);
        //如果单据的物流状态时null/0则表示时初始化，此时可以把单据的物流状态更新为已发货，如果当前时其它的物流状态则不更新，否则状态就倒退了
        Integer currentLogisticStatus = waybillDO.getLogisticStatus();
        if(currentLogisticStatus == null || currentLogisticStatus.compareTo(LogisticNodeTypeEnum.INIT.getType()) == 0){
            confirmWayBill.setLogisticStatus(LogisticNodeTypeEnum.DELIVERYED.getType());
        }
        logisticWaybillMapper.updateByPrimaryKeySelective(confirmWayBill);
        //TODO wzy 发短信
    }

    /**
     * @Des 拼接确认发货需要保存的物流信息
     * @Date 2021/5/25 14:27
     * @Author wangzhaoyu
     * @Param [wayBillId]
     * @Return xcmg.device.dao.entity.logistic.LogisticNodeRecordDO
     */
    private LogisticNodeRecordDO assembleDeliveryLogisticRecordSave(String wayBillId,String deliveryUserId,String deliveryUserName) throws Exception {
        LogisticNodeRecordDO result = new LogisticNodeRecordDO();
        ActionResult<String> idResult = fastGenClient.textGuid();
        if (idResult == null || idResult.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        Date currentTime = new Date();
        result.setId(idResult.getValue());
        result.setWayBillId(wayBillId);
        result.setRecordUserName(deliveryUserName);
        result.setRecordUserId(deliveryUserId);
        result.setRecordTime(currentTime);
        result.setIsDel(0);
        result.setNodeInfo("发货人："+deliveryUserName);
        result.setCreateDate(currentTime);
        result.setNodeType(LogisticNodeTypeEnum.DELIVERYED.getType());
        result.setRecordType(LogisticRecodeOperateTypeEnum.MANUAL.getType());
        return result;
    }

    /**
     * @Des 创建运费结算单时选择物流运单的接口
     * @Date 2021/5/20 19:20
     * @Author wangzhaoyu
     * @Param [orgId, condition]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.LogisticWaybillSelectResultVO>
     */
    public PageCommonVO<LogisticWaybillSelectResultVO> waybillsSelect(String orgId,SearchCommonVO<LogisticWayBillListQueryParamVO> condition) throws Exception {
        LogisticWayBillListQueryParamVO filters = condition.getFilters();
        String shippingMethodId = filters.getShippingMethodId();
        if(StringUtils.isEmpty(shippingMethodId)){
            throw new Exception("发运方式为必选搜索条件");
        }
        Integer pageNum = condition.getPageNum();
        Integer pageSize = condition.getPageSize();
        PageHelperPlus.startPage(pageNum, pageSize);
        List<LogisticWaybillSelectResultVO> logisticWaybills = logisticWaybillMapper.waybillsSelect(orgId, filters);
        PageCommonVO<LogisticWaybillSelectResultVO> result = new PageCommonVO();
        result.setPageInfo(new PageInfo(logisticWaybills));
        result.setPageInfoList(logisticWaybills);
        return result;
    }

    /**
     * @Des 保存物流运费结算单
     * @Date 2021/5/19 16:39
     * @Author wangzhaoyu
     * @Param [saveParam, operate ： 0=保存，1=提交]
     * @Return void
     */
    @Transactional
    public void saveWayBillFee(LogisticWaybillFeeSaveVO saveParam,String orgId,String createUserId,String createUserName,int operate) throws Exception {
        //主表数据保存
        LogisticWaybillFeeDO logisticWaybillFeeDO = assembleBillFeeSaveDO(saveParam,orgId,createUserId,createUserName,operate);
        logisticWaybillFeeMapper.insert(logisticWaybillFeeDO);
        //子表数据保存
        List<LogisticWaybillFeeDetailDO> details = assembleBillFeeDetailsSaveDO(saveParam,logisticWaybillFeeDO);
        logisticWaybillFeeDetailMapper.batchInsert(details);
    }

    /**
     * @Des 更新物流运费计算单
     * @Date 2021/5/20 10:26
     * @Author wangzhaoyu
     * @Param [saveParam, operate]
     * @Return void
     */
    @Transactional
    public void updateWayBillFee(LogisticWaybillFeeSaveVO saveParam,int operate) throws Exception {
        LogisticWaybillFeeSaveVO.HeadInfo headInfo = saveParam.getHeadInfo();
        String feeId = headInfo.getId();
        //更新主表数据
        LogisticWaybillFeeDO waybillFeeDoUpdate = assembleBillFeeUpdateDO(saveParam,operate);
        logisticWaybillFeeMapper.updateByPrimaryKeySelective(waybillFeeDoUpdate);
        //更新子表数据
        List<LogisticWaybillFeeDetailDO> logisticWaybillFeeDetailsUpdate = assembleWayBillFeeDetailUpdate(saveParam);
        List<LogisticWaybillFeeDetailDO> oldLogisticWaybillFeeDetails = logisticWaybillFeeDetailMapper.selectByFeeId(feeId);
        //用于保存本次操作新增的detail数据
        List<LogisticWaybillFeeDetailDO> needInsert = new LinkedList<>();
        for(LogisticWaybillFeeDetailDO detailUpdate : logisticWaybillFeeDetailsUpdate){
            //如果包含，老记录中有，说明不需要删除，从集合中remove掉,剩余的就是需要删除的
            if(oldLogisticWaybillFeeDetails.contains(detailUpdate)){
                oldLogisticWaybillFeeDetails.remove(detailUpdate);
            }else{
                needInsert.add(detailUpdate);
            }
        }
        //批量新增
        logisticWaybillFeeDetailMapper.batchInsert(needInsert);
        //批量删除
        logisticWaybillFeeDetailMapper.deleteBatch(oldLogisticWaybillFeeDetails);
    }

    /**
     * @Des 更新运费结算单据时拼接详情信息
     * @Date 2021/5/20 11:10
     * @Author wangzhaoyu
     * @Param [saveParam]
     * @Return java.util.List<xcmg.device.dao.entity.logistic.LogisticWaybillFeeDetailDO>
     */
    private List<LogisticWaybillFeeDetailDO> assembleWayBillFeeDetailUpdate(LogisticWaybillFeeSaveVO saveParam){
        List<LogisticWaybillFeeSaveVO.Detail> details = saveParam.getDetails();
        List<LogisticWaybillFeeDetailDO> result = new LinkedList<>();
        for(LogisticWaybillFeeSaveVO.Detail detail : details){
            LogisticWaybillFeeDetailDO waybillFeeDetailDO = new LogisticWaybillFeeDetailDO();
            String wayBillNo = detail.getWayBillNo();
            String id = detail.getId();
            waybillFeeDetailDO.setId(id);
            waybillFeeDetailDO.setWayBillNo(wayBillNo);
            result.add(waybillFeeDetailDO);
        }
        return result;
    }

    /**
     * @Des 更新操作，拼接更新的主表信息
     * @Date 2021/5/20 10:32
     * @Author wangzhaoyu
     * @Param [saveParam, operate]
     * @Return xcmg.device.dao.entity.logistic.LogisticWaybillFeeDO
     */
    private LogisticWaybillFeeDO assembleBillFeeUpdateDO(LogisticWaybillFeeSaveVO saveParam, int operate) throws Exception {
        LogisticWaybillFeeSaveVO.HeadInfo headInfo = saveParam.getHeadInfo();
        String id = headInfo.getId();
        BigDecimal totalFee = headInfo.getTotalFee();
        LogisticWaybillFeeDO oldLogisticWaybillFeeDO = logisticWaybillFeeMapper.selectByPrimaryKey(id);
        if(oldLogisticWaybillFeeDO == null){
            throw new Exception("未找到单据");
        }
        LogisticWaybillFeeDO result = new LogisticWaybillFeeDO();
        result.setId(id);
        result.setTotalFee(totalFee);
        if(operate == 1){
            result.setStatus(LogisticWayBillFeeStatusEnum.SUBMIT.getStatus());
        }else{
            result.setStatus(LogisticWayBillFeeStatusEnum.SAVE.getStatus());
        }
        return result;
    }

    @SneakyThrows
    private List<LogisticWaybillFeeDetailDO> assembleBillFeeDetailsSaveDO(LogisticWaybillFeeSaveVO saveParam,LogisticWaybillFeeDO logisticWaybillFeeDO){
        List<LogisticWaybillFeeSaveVO.Detail> details = saveParam.getDetails();
        List<LogisticWaybillFeeDetailDO> result = new LinkedList<>();
        for(LogisticWaybillFeeSaveVO.Detail detail : details){
            String wayBillNo = detail.getWayBillNo();
            LogisticWaybillFeeDetailDO detailDoSave = new LogisticWaybillFeeDetailDO();
            ActionResult<String> idResult = fastGenClient.textGuid();
            if (idResult == null || idResult.getCode() != 0) {
                throw new Exception("生成唯一标识失败");
            }
            detailDoSave.setId(idResult.getValue());
            detailDoSave.setWayBillFeeId(logisticWaybillFeeDO.getId());
            detailDoSave.setWayBillNo(wayBillNo);
            result.add(detailDoSave);
        }
        return result;
    }

    private LogisticWaybillFeeDO assembleBillFeeSaveDO(LogisticWaybillFeeSaveVO saveParam,String orgId,String createUserId,String createUserName, int operate) throws Exception {
        LogisticWaybillFeeSaveVO.HeadInfo headInfo = saveParam.getHeadInfo();
        BigDecimal totalFee = headInfo.getTotalFee();
        LogisticWaybillFeeDO saveDO = new LogisticWaybillFeeDO();
        ActionResult<String> idResult = fastGenClient.textGuid();
        if (idResult == null || idResult.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        String id = idResult.getValue();
        String feeNo = genDocumentService.genDocumentNo(BillDesc.LogisticWaybillFee, orgId);
        saveDO.setId(id);
        saveDO.setOrgId(orgId);
        saveDO.setWayBillFeeNo(feeNo);
        saveDO.setShippingMethod(headInfo.getShippingMethod());
        saveDO.setShippingMethodId(headInfo.getShippingMethodId());
        saveDO.setTotalFee(totalFee);
        saveDO.setCreateUserId(createUserId);
        saveDO.setCreateUserName(createUserName);
        saveDO.setCreateDate(new Date());
        if(operate == 1){
            saveDO.setStatus(LogisticWayBillFeeStatusEnum.SUBMIT.getStatus());
        }else{
            saveDO.setStatus(LogisticWayBillFeeStatusEnum.SAVE.getStatus());
        }
        return saveDO;
    }

    /**
     * @Des 运费结算单列表查询
     * @Date 2021/5/20 14:56
     * @Author wangzhaoyu
     * @Param [condition, orgId]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.LogisticWaybillFeeListingResultVO>
     */
    public PageCommonVO<LogisticWaybillFeeListingResultVO> listingLogisticWayBillFees(SearchCommonVO<LogisticWaybillFeeListQueryParamVO> condition, String orgId) {
        LogisticWaybillFeeListQueryParamVO filters = condition.getFilters();
        Integer pageNum = condition.getPageNum();
        Integer pageSize = condition.getPageSize();
        PageHelperPlus.startPage(pageNum, pageSize);
        List<LogisticWaybillFeeDO> logisticWaybillFeeDOS = logisticWaybillFeeMapper.selectByFilter(orgId, filters);
        List<LogisticWaybillFeeListingResultVO> datas = new LinkedList<>();
        for(LogisticWaybillFeeDO waybillFeeDO : logisticWaybillFeeDOS){
            LogisticWaybillFeeListingResultVO data = new LogisticWaybillFeeListingResultVO();
            data.setAfterAuditTotalFee(waybillFeeDO.getAfterAuditTotalFee());
            data.setApprovalDate(waybillFeeDO.getApprovalDate());
            data.setApprovalUserId(waybillFeeDO.getApprovalUserId());
            data.setApprovalUserName(waybillFeeDO.getApprovalUserName());
            data.setAuditDate(waybillFeeDO.getAuditDate());
            data.setAuditUserId(waybillFeeDO.getAuditUserId());
            data.setAuditUserName(waybillFeeDO.getAuditUserName());
            data.setCreateDate(waybillFeeDO.getCreateDate());
            data.setCreateUserId(waybillFeeDO.getCreateUserId());
            data.setCreateUserName(waybillFeeDO.getCreateUserName());
            data.setShippingMethod(waybillFeeDO.getShippingMethod());
            data.setShippingMethodId(waybillFeeDO.getShippingMethodId());
            data.setStatus(waybillFeeDO.getStatus());
            data.setTotalFee(waybillFeeDO.getTotalFee());
            data.setWayBillFeeNo(waybillFeeDO.getWayBillFeeNo());
            datas.add(data);
        }
        PageCommonVO<LogisticWaybillFeeListingResultVO> result = new PageCommonVO<>();
        result.setPageInfo(new PageInfo(logisticWaybillFeeDOS));
        result.setPageInfoList(datas);
        return result;
    }

    /**
     * @Des 运费结算单审核
     * @Date 2021/5/20 15:59
     * @Author wangzhaoyu
     * @Param [userId, userName, auditPass ： true 表示审核通过，false:表示审核拒绝, auditVO]
     * @Return void
     */
    public void auditWaybillFee(String userId, String userName, boolean auditPass, LogisticWaybillFeeAuditVO auditVO) throws Exception {
        String id = auditVO.getId();
        LogisticWaybillFeeDO waybillFeeDO = logisticWaybillFeeMapper.selectByPrimaryKey(id);
        if(waybillFeeDO == null){
            throw new Exception("未找到记录");
        }
        Integer oldStatus = waybillFeeDO.getStatus();
        if(oldStatus == null || oldStatus.compareTo(LogisticWayBillFeeStatusEnum.SUBMIT.getStatus()) != 0){
            throw new Exception("只能审核已提交的结算单");
        }
        LogisticWaybillFeeDO auditDo = new LogisticWaybillFeeDO();
        auditDo.setId(id);
        auditDo.setAuditDate(new Date());
        auditDo.setAuditRemark(auditVO.getAuditRemark());
        auditDo.setAuditUserId(userId);
        auditDo.setAuditUserName(userName);
        auditDo.setAfterAuditTotalFee(auditVO.getAfterAuditTotalFee());
        auditDo.setAlterationRatio(auditVO.getAlterationRatio());
        if(auditPass){
            auditDo.setStatus(LogisticWayBillFeeStatusEnum.AUDIT_PASS.getStatus());
        }else{
            auditDo.setStatus(LogisticWayBillFeeStatusEnum.AUDIT_REJECT.getStatus());
        }
        logisticWaybillFeeMapper.updateByPrimaryKeySelective(auditDo);
    }

    /**
     * @Des 运费结算单审批通过
     * @Date 2021/5/20 17:17
     * @Author wangzhaoyu
     * @Param [userId, userName, approvalPass ： true表示通过，false表示拒绝, approval]
     * @Return void
     */
    public void approvalWaybillFee(String userId, String userName, boolean approvalPass, LogisticWaybillFeeApprovalVO approval) throws Exception {

        String id = approval.getId();
        LogisticWaybillFeeDO oldwaybillFeeDO = logisticWaybillFeeMapper.selectByPrimaryKey(id);
        if(oldwaybillFeeDO == null){
            throw new Exception("未找到记录");
        }
        Integer status = oldwaybillFeeDO.getStatus();
        if(status == null || status.compareTo(LogisticWayBillFeeStatusEnum.AUDIT_PASS.getStatus()) != 0){
            throw new Exception("只能审批已审核通过的结算单");
        }
        LogisticWaybillFeeDO approvalFeeDO = new LogisticWaybillFeeDO();
        approvalFeeDO.setId(id);
        approvalFeeDO.setApprovalDate(new Date());
        approvalFeeDO.setApprovalUserId(userId);
        approvalFeeDO.setApprovalUserName(userName);
        approvalFeeDO.setApprovalRemark(approval.getApprovalRemark());
        if(approvalPass){
            approvalFeeDO.setStatus(LogisticWayBillFeeStatusEnum.APPROVAL_PASS.getStatus());
        }else{
            approvalFeeDO.setStatus(LogisticWayBillFeeStatusEnum.APPROVAL_REJECT.getStatus());
        }
        logisticWaybillFeeMapper.updateByPrimaryKeySelective(approvalFeeDO);
    }

    /**
     * @Des 展示物流运费结算单的信息，包括表头和详情
     * @Date 2021/5/20 19:36
     * @Author wangzhaoyu
     * @Param [id]
     * @Return xcmg.device.service.vo.logistic.LogisticWaybillFeeViewResponseVO
     */
    public LogisticWaybillFeeViewResponseVO viewBillFeeInfo(String id) throws Exception {
        LogisticWaybillFeeDO waybillFeeDO = logisticWaybillFeeMapper.selectByPrimaryKey(id);
        if(waybillFeeDO == null){
            throw new Exception("未查询到单据信息");
        }
        LogisticWaybillFeeViewResponseVO result = new LogisticWaybillFeeViewResponseVO();
        LogisticWaybillFeeViewResponseVO.HeadInfo headInfo = new LogisticWaybillFeeViewResponseVO.HeadInfo();
        headInfo.setId(waybillFeeDO.getId());
        headInfo.setAfterAuditTotalFee(waybillFeeDO.getAfterAuditTotalFee());
        headInfo.setAlterationRatio(waybillFeeDO.getAlterationRatio());
        headInfo.setShippingMethod(waybillFeeDO.getShippingMethod());
        headInfo.setShippingMethodId(waybillFeeDO.getShippingMethodId());
        headInfo.setTotalFee(waybillFeeDO.getTotalFee());
        headInfo.setWayBillFeeNo(waybillFeeDO.getWayBillFeeNo());

        //查询子表信息
        List<LogisticWaybillFeeViewResponseVO.Detail> details = logisticWaybillFeeDetailMapper.viewDetail(id);
        result.setHeadInfo(headInfo);
        result.setDetails(details);
        return result;
    }

    public FeePageViewWaybillInfoVO feePageViewWaybillInfo(String wayBillId) {

        FeePageViewWaybillInfoVO result = logisticWaybillMapper.feePageViewWaybillInfo(wayBillId);
        return result;
    }

    /**
     * @Des 打印物流运单信息
     * @Date 2021/5/22 16:55
     * @Author wangzhaoyu
     * @Param [id]
     * @Return xcmg.device.service.vo.logistic.LogisticBillwayPrintVO
     */
    public LogisticBillwayPrintVO printLogisticBillway(String id) throws Exception {
        //获取表头信息
        LogisticWaybillDO logisticWaybillDO = logisticWaybillMapper.selectByPrimaryKey(id);
        if(logisticWaybillDO == null){
            throw new Exception("未找到记录");
        }
        //获取表体详情信息
        LogisticBillwayPrintVO result = new LogisticBillwayPrintVO();
        LogisticBillwayPrintVO.HeadInfo headInfoResult = assembleWayBillPrintHeadInfo(logisticWaybillDO);
        //获取单据零件详情信息
        String businessType = logisticWaybillDO.getBusinessType();
        result.setHeadInfo(headInfoResult);
        assemblePrintMaterials(businessType,result,logisticWaybillDO.getId());
        return result;
    }


    private void assemblePrintMaterials(String businessType, LogisticBillwayPrintVO result, String wayBillId){
        //不是发运交接单也不是三包出库单则直接拼接空集
        if(StringUtils.isEmpty(businessType)
                || (!businessType.equals(BillDesc.DeliveryReceiptNo.getDesc()) && (!businessType.equals(BillDesc.ThreeOut.getDesc())))){
            return ;
        }
        List<LogisticWayLinkBillDetailVO> logisticsWayLinkBillDetails;
        //判断如果是发运交接单则通过与发运交接单关联获取关联单据信息
        if(businessType.equals(BillDesc.DeliveryReceiptNo.getDesc())){
            logisticsWayLinkBillDetails = logisticWaybillDetailMapper.deliveryReceiptTypeLinkDetails(wayBillId);
        }else if(businessType.equals(BillDesc.ThreeOut.getDesc())){
            //如果是三包出库单则通过与三包出库单关联获取关联单据信息
            logisticsWayLinkBillDetails = logisticWaybillDetailMapper.threeOutTypeLinkDetails(wayBillId);
        }else{
            return ;
        }
        //拼接关联单据详情
        List<LogisticBillwayPrintVO.LinkBillDetail> linkBillDetails = new LinkedList<>();
        for(LogisticWayLinkBillDetailVO linkBillDetail : logisticsWayLinkBillDetails){
            BigDecimal amount = linkBillDetail.getAmount();
            String businessOrder = linkBillDetail.getBusinessOrder();
            String materailsNo = linkBillDetail.getMaterailsNo();
            String materialsDesc = linkBillDetail.getMaterialsDesc();
            String unit = linkBillDetail.getUnit();
            LogisticBillwayPrintVO.LinkBillDetail linkDetail = new LogisticBillwayPrintVO.LinkBillDetail();
            linkDetail.setAmount(amount);
            linkDetail.setBusinessOrder(businessOrder);
            linkDetail.setMaterailsNo(materailsNo);
            linkDetail.setMaterialsDesc(materialsDesc);
            linkDetail.setUnit(unit);
            linkBillDetails.add(linkDetail);
        }
        result.setLinkBillDetails(linkBillDetails);
    }

    /**
     * @Des 打印物流运单单据表头
     * @Date 2021/5/22 17:02
     * @Author wangzhaoyu
     * @Param [logisticWaybillDO]
     * @Return xcmg.device.service.vo.logistic.LogisticBillwayPrintVO.HeadInfo
     */
    private LogisticBillwayPrintVO.HeadInfo assembleWayBillPrintHeadInfo(LogisticWaybillDO logisticWaybillDO) {
        LogisticBillwayPrintVO.HeadInfo result = new LogisticBillwayPrintVO.HeadInfo();
        result.setWayBillNo(logisticWaybillDO.getWayBillNo());
        result.setReceiverTel(logisticWaybillDO.getReceiverTel());
        result.setReceiverName(logisticWaybillDO.getReceiverName());
        result.setReceiverAddress(logisticWaybillDO.getReceiverAddress());
        result.setDeliveryTime(logisticWaybillDO.getDeliveryTime());
        result.setCarrierOrgName(logisticWaybillDO.getCarrierOrgName());
        result.setDealerOrgName(logisticWaybillDO.getDealerOrgName());
        result.setShippingMethod(logisticWaybillDO.getShippingMethod());
        result.setAuditRemark(logisticWaybillDO.getAuditRemark());
        result.setAuditUserName(logisticWaybillDO.getAuditUserName());
        result.setCreateDate(logisticWaybillDO.getCreateDate());
        result.setCreateUserName(logisticWaybillDO.getCreateUserName());
        result.setStatus(logisticWaybillDO.getStatus());
        return result;
    }

    public LogisticWaybillFeePrintVO printLogisticBillwayFee(String id) throws Exception {
        LogisticWaybillFeeDO waybillFeeDO = logisticWaybillFeeMapper.selectByPrimaryKey(id);
        if(waybillFeeDO == null){
            throw new Exception("未查询到单据信息");
        }
        LogisticWaybillFeePrintVO result = new LogisticWaybillFeePrintVO();
        LogisticWaybillFeePrintVO.HeadInfo headInfo = new LogisticWaybillFeePrintVO.HeadInfo();
        headInfo.setAfterAuditTotalFee(waybillFeeDO.getAfterAuditTotalFee());
        headInfo.setAlterationRatio(waybillFeeDO.getAlterationRatio());
        headInfo.setShippingMethod(waybillFeeDO.getShippingMethod());
        headInfo.setTotalFee(waybillFeeDO.getTotalFee());
        headInfo.setWayBillFeeNo(waybillFeeDO.getWayBillFeeNo());
        headInfo.setApprovalDate(waybillFeeDO.getApprovalDate());
        headInfo.setApprovalUserName(waybillFeeDO.getApprovalUserName());
        headInfo.setAuditDate(waybillFeeDO.getAuditDate());
        headInfo.setAuditUserName(waybillFeeDO.getAuditUserName());
        headInfo.setCreateDate(waybillFeeDO.getCreateDate());
        headInfo.setCreateUserName(waybillFeeDO.getCreateUserName());
        headInfo.setStatus(waybillFeeDO.getStatus());
        //查询子表信息
        List<LogisticWaybillFeePrintVO.Detail> details = logisticWaybillFeeDetailMapper.printDetail(id);
        result.setHeadInfo(headInfo);
        result.setDetails(details);
        return result;
    }

    /**
     * @Des 物流状态页面列表分页数据
     * @Date 2021/5/24 16:06
     * @Author wangzhaoyu
     * @Param [condition]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.LogisticStatusListingWaybillVO>
     */
    public PageCommonVO<LogisticStatusListingWaybillVO> logisticStatusListingWaybills(String orgId,SearchCommonVO<LogisticWayBillListQueryParamVO> condition) {
        Integer pageNum = condition.getPageNum();
        Integer pageSize = condition.getPageSize();
        LogisticWayBillListQueryParamVO filters = condition.getFilters();
        filters.setDeliveryStatus(1);
        PageHelperPlus.startPage(pageNum, pageSize);
        List<LogisticWaybillDO> logisticWaybillDOS = logisticWaybillMapper.selectByListFilter(orgId, filters);
        List<LogisticStatusListingWaybillVO> dataLst = new LinkedList<>();
        for(LogisticWaybillDO waybillDO : logisticWaybillDOS){
            LogisticStatusListingWaybillVO dataVO = new LogisticStatusListingWaybillVO();
            dataVO.setBusinessType(waybillDO.getBusinessType());
            dataVO.setCarrierOrgName(waybillDO.getCarrierOrgName());
            dataVO.setCreateUserName(waybillDO.getCreateUserName());
            dataVO.setDealerOrgId(waybillDO.getDealerOrgId());
            dataVO.setDealerOrgName(waybillDO.getDealerOrgName());
            dataVO.setExpectArrivalTime(waybillDO.getExpectArrivalTime());
            dataVO.setId(waybillDO.getId());
            dataVO.setLogisticStatus(waybillDO.getLogisticStatus());
            dataVO.setReceiverName(waybillDO.getReceiverName());
            dataVO.setRemark(waybillDO.getRemark());
            dataVO.setShippingMethod(waybillDO.getShippingMethod());
            dataVO.setShippingMethodId(waybillDO.getShippingMethodId());
            dataVO.setWayBillNo(waybillDO.getWayBillNo());
            dataVO.setCreateDate(waybillDO.getCreateDate());
            dataLst.add(dataVO);
        }
        PageCommonVO<LogisticStatusListingWaybillVO> pageCommonVO = new PageCommonVO<>();
        pageCommonVO.setPageInfo(new PageInfo(logisticWaybillDOS));
        pageCommonVO.setPageInfoList(dataLst);
        return pageCommonVO;
    }

    /**
     * @Des 物流信息录入
     * @Date 2021/5/25 10:17
     * @Author wangzhaoyu
     * @Param [enterVO]
     * @Return void
     */
    @Transactional
    public void saveLogisticRecord(String userId,String userName,LogisticNodeRecordEnterVO enterVO) throws Exception {
        String wayBillId = enterVO.getWayBillId();
        LogisticWaybillDO waybillDO = logisticWaybillMapper.selectByPrimaryKey(wayBillId);
        if(waybillDO == null){
            throw new Exception("未查询到物流运单记录");
        }
        //物流记录中插入记录
        LogisticNodeRecordDO logisticNodeRecordSave = assembleLogisticRecordEnterSave(userId,userName,enterVO);
        logisticNodeRecordMapper.insertSelective(logisticNodeRecordSave);
        //更新物流运单的物流状态为运输中（只有单据的物流状态是已发货或者是初始化的时候才进行更新）
        Integer logisticStatus = waybillDO.getLogisticStatus();
        if(logisticStatus == null || logisticStatus.compareTo(LogisticNodeTypeEnum.INIT.getType()) == 0
                || logisticStatus.compareTo(LogisticNodeTypeEnum.DELIVERYED.getType()) == 0){
            LogisticWaybillDO logisticStatusUpdateDO = new LogisticWaybillDO();
            logisticStatusUpdateDO.setId(wayBillId);
            logisticStatusUpdateDO.setLogisticStatus(LogisticNodeTypeEnum.TRANSPORTING.getType());
            logisticWaybillMapper.updateByPrimaryKeySelective(logisticStatusUpdateDO);
        }
    }

    /**
     * @Des 拼接物流信息录入的保存实体
     * @Date 2021/5/25 15:41
     * @Author wangzhaoyu
     * @Param []
     * @Return xcmg.device.dao.entity.logistic.LogisticNodeRecordDO
     */
    private LogisticNodeRecordDO assembleLogisticRecordEnterSave(String userId,String userName,LogisticNodeRecordEnterVO enterVO) throws Exception {
        String wayBillId = enterVO.getWayBillId();
        String nodeInfo = enterVO.getNodeInfo();
        Date recordTime = enterVO.getRecordTime();
        LogisticNodeRecordDO logisticNodeRecordSave = new LogisticNodeRecordDO();
        ActionResult<String> idResult = fastGenClient.textGuid();
        if (idResult == null || idResult.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        String id = idResult.getValue();
        logisticNodeRecordSave.setCreateDate(new Date());
        logisticNodeRecordSave.setId(id);
        logisticNodeRecordSave.setNodeType(LogisticNodeTypeEnum.TRANSPORTING.getType());
        logisticNodeRecordSave.setNodeInfo(nodeInfo);
        logisticNodeRecordSave.setIsDel(0);
        logisticNodeRecordSave.setRecordTime(recordTime);
        logisticNodeRecordSave.setRecordType(LogisticRecodeOperateTypeEnum.MANUAL.getType());
        logisticNodeRecordSave.setRecordUserId(userId);
        logisticNodeRecordSave.setRecordUserName(userName);
        logisticNodeRecordSave.setWayBillId(wayBillId);
        return logisticNodeRecordSave;
    }

    /**
     * @Des 获取物流运单的物流信息
     * @Date 2021/5/25 14:04
     * @Author wangzhaoyu
     * @Param [wayBillId]
     * @Return java.util.List<xcmg.device.service.vo.logistic.LogisticNodeRecordVO>
     */
    public List<LogisticNodeRecordVO> getLogisticRecords(String wayBillId) {
        List<LogisticNodeRecordDO> logisticNodeRecords = logisticNodeRecordMapper.selectByWayBillId(wayBillId);
        List<LogisticNodeRecordVO> result = new LinkedList<>();
        for(LogisticNodeRecordDO recordDO : logisticNodeRecords){
            LogisticNodeRecordVO nodeRecord = new LogisticNodeRecordVO();
            nodeRecord.setId(recordDO.getId());
            nodeRecord.setNodeInfo(recordDO.getNodeInfo());
            nodeRecord.setRecordTime(recordDO.getRecordTime());
            nodeRecord.setWayBillId(recordDO.getWayBillId());
            result.add(nodeRecord);
        }
        return result;
    }

    /**
     * @Des 物流运单到货确认
     * @Date 2021/5/25 15:35
     * @Author wangzhaoyu
     * @Param [arrivalConfirm]
     * @Return void
     */
    @Transactional
    public void arrivalConfirm(String confirmUserId,String confirmUserName,LogisticWaybillArrivalConfirmVO arrivalConfirm) throws Exception {
        Date arrivalTime = arrivalConfirm.getArrivalTime();
        String wayBillId = arrivalConfirm.getWayBillId();
        if(StringUtils.isEmpty(wayBillId)){
            throw new Exception(ErrorCode.IllegalArument.getDesc());
        }
        if(arrivalTime == null){
            throw new Exception("请输入到货日期");
        }
        LogisticWaybillDO waybillDO = logisticWaybillMapper.selectByPrimaryKey(wayBillId);
        if(waybillDO == null){
            throw new Exception("未查询到物流运单");
        }
        //新增已到货物流记录
        LogisticNodeRecordDO logisticNodeRecordDO = assembleLogisticArrivalRecord(confirmUserId, confirmUserName, waybillDO);
        logisticNodeRecordMapper.insertSelective(logisticNodeRecordDO);
        //修改物流运单的物流状态为已到货状态（如果是当前状态是已签收/已到货则不更新）
        Integer currentLogisticStatus = waybillDO.getLogisticStatus();
        if(currentLogisticStatus == null ||
                (currentLogisticStatus.compareTo(LogisticNodeTypeEnum.ARRIVALED.getType()) != 0)
                        && currentLogisticStatus.compareTo(LogisticNodeTypeEnum.SIGNED.getType()) != 0){
            LogisticWaybillDO logisticStatusUpdateDO = new LogisticWaybillDO();
            logisticStatusUpdateDO.setId(wayBillId);
            logisticStatusUpdateDO.setLogisticStatus(LogisticNodeTypeEnum.ARRIVALED.getType());
            logisticStatusUpdateDO.setArrivalTime(new Date());
            logisticWaybillMapper.updateByPrimaryKeySelective(logisticStatusUpdateDO);
        }
    }

    private LogisticNodeRecordDO assembleLogisticArrivalRecord(String userId,String userName,LogisticWaybillDO waybillDO) throws Exception {
        LogisticNodeRecordDO arrivalConfirmDO = new LogisticNodeRecordDO();
        Date currentTime = new Date();
        ActionResult<String> idResult = fastGenClient.textGuid();
        if (idResult == null || idResult.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        arrivalConfirmDO.setRecordType(LogisticRecodeOperateTypeEnum.MANUAL.getType());
        arrivalConfirmDO.setNodeType(LogisticNodeTypeEnum.ARRIVALED.getType());
        arrivalConfirmDO.setCreateDate(currentTime);
        arrivalConfirmDO.setNodeInfo("货物已到目的地"+waybillDO.getReceiverAddress());
        arrivalConfirmDO.setIsDel(0);
        arrivalConfirmDO.setRecordTime(currentTime);
        arrivalConfirmDO.setRecordUserId(userId);
        arrivalConfirmDO.setRecordUserName(userName);
        arrivalConfirmDO.setWayBillId(waybillDO.getId());
        arrivalConfirmDO.setId(idResult.getValue());
        return arrivalConfirmDO;
    }

    /**
     * @Des 签收物流运单接口
     * @Date 2021/5/25 17:13
     * @Author wangzhaoyu
     * @Param [wayBillId]
     * @Return void
     */
    public void signConfirm(String userId,String userName,String wayBillId) throws Exception {
        LogisticWaybillDO waybillDO = logisticWaybillMapper.selectByPrimaryKey(wayBillId);
        if(waybillDO == null){
            throw new Exception("未查询到物流运单");
        }
        //插入签收的物流记录
        LogisticNodeRecordDO logisticNodeRecord = assembleLogisticSignRecord(userId, userName, waybillDO);
        logisticNodeRecordMapper.insertSelective(logisticNodeRecord);
        //更新物流单据的物流状态为已签收
        LogisticWaybillDO logisticStatusUpdateDO = new LogisticWaybillDO();
        logisticStatusUpdateDO.setId(wayBillId);
        logisticStatusUpdateDO.setLogisticStatus(LogisticNodeTypeEnum.SIGNED.getType());
        logisticStatusUpdateDO.setSignTime(new Date());
        logisticWaybillMapper.updateByPrimaryKeySelective(logisticStatusUpdateDO);
    }

    /**
     * @Des 拼接签收的物流记录信息
     * @Date 2021/5/25 18:47
     * @Author wangzhaoyu
     * @Param [userId, userName, waybillDO]
     * @Return xcmg.device.dao.entity.logistic.LogisticNodeRecordDO
     */
    private LogisticNodeRecordDO assembleLogisticSignRecord(String userId,String userName,LogisticWaybillDO waybillDO) throws Exception {
        LogisticNodeRecordDO arrivalConfirmDO = new LogisticNodeRecordDO();
        Date currentTime = new Date();
        ActionResult<String> idResult = fastGenClient.textGuid();
        if (idResult == null || idResult.getCode() != 0) {
            throw new Exception("生成唯一标识失败");
        }
        arrivalConfirmDO.setRecordType(LogisticRecodeOperateTypeEnum.MANUAL.getType());
        arrivalConfirmDO.setNodeType(LogisticNodeTypeEnum.SIGNED.getType());
        arrivalConfirmDO.setCreateDate(currentTime);
        arrivalConfirmDO.setNodeInfo("签收人:"+userName);
        arrivalConfirmDO.setIsDel(0);
        arrivalConfirmDO.setRecordTime(currentTime);
        arrivalConfirmDO.setRecordUserId(userId);
        arrivalConfirmDO.setRecordUserName(userName);
        arrivalConfirmDO.setWayBillId(waybillDO.getId());
        arrivalConfirmDO.setId(idResult.getValue());
        return arrivalConfirmDO;
    }

    /**
     * @Des 物流运单自动签收操作
     * @Date 2021/5/25 20:31
     * @Author wangzhaoyu
     * @Param []
     * @Return void
     */
    @Transactional
    public void autoSignWaybills(String orgId) throws Exception {
        Date currentTime = new Date();
        int groupSize = 900;
       //获取需要自动签收的物流运单
        List<String> needAutoSignWaybillIds = logisticWaybillMapper.needAutoSignWaybills(orgId);
        if(CollectionUtils.isEmpty(needAutoSignWaybillIds)){
            return ;
        }
       //自动签收操作，分批次，每900条自动自动批量签收
        List<List<String>> groupsLst = new LinkedList<>();
        int times = needAutoSignWaybillIds.size()/groupSize;
        int ot = needAutoSignWaybillIds.size()%groupSize;
        for(int i = 0 ;i < times ; i++){
            List<String> groups = needAutoSignWaybillIds.subList(i * groupSize, (i + 1) * groupSize);
            groupsLst.add(groups);
        }
        if(ot > 0){
            List<String> groups = needAutoSignWaybillIds.subList(times * groupSize, needAutoSignWaybillIds.size());
            groupsLst.add(groups);
        }
        //分批次处理，1000条一次批处理
        for(List<String> batchHandleLst : groupsLst){
            //批量更新物流状态并更新签收时间
            logisticWaybillMapper.batchSign(batchHandleLst,currentTime);
            //批量插入签收的物流状态
            List<LogisticNodeRecordDO> signRecords = assembleBatchInsertLogisticRecord(currentTime, batchHandleLst);
            logisticNodeRecordMapper.batchInsertLogisticRecord(signRecords);
        }
    }

    private List<LogisticNodeRecordDO> assembleBatchInsertLogisticRecord(Date signTime,List<String> ids) throws Exception {
        List<LogisticNodeRecordDO> result = new LinkedList<>();
        for(String wayBillId : ids){
            LogisticNodeRecordDO recordSave = new LogisticNodeRecordDO();
            ActionResult<String> idResult = fastGenClient.textGuid();
            if (idResult == null || idResult.getCode() != 0) {
                throw new Exception("生成唯一标识失败");
            }
            recordSave.setId(idResult.getValue());
            recordSave.setWayBillId(wayBillId);
            recordSave.setRecordUserName("系统自动");
            recordSave.setRecordUserId("0000");
            recordSave.setIsDel(0);
            recordSave.setNodeInfo("系统自动签收");
            recordSave.setRecordTime(signTime);
            recordSave.setCreateDate(signTime);
            recordSave.setNodeType(LogisticNodeTypeEnum.SIGNED.getType());
            recordSave.setRecordType(LogisticRecodeOperateTypeEnum.AUTO.getType());
            result.add(recordSave);
        }
        return result;
    }


    /**
     * @Des 获取物流运单表中的所有orgId
     * @Date 2021/5/25 20:36
     * @Author wangzhaoyu
     * @Param []
     * @Return java.util.List<java.lang.String>
     */
    public List<String> LogisticWaybillAllOrgId(){
        List<String> orgIds = logisticWaybillMapper.distinctOrgId();
        return orgIds;
    }

    /**
     * @Des 物流状态看板
     * @Date 2021/5/27 15:42
     * @Author wangzhaoyu
     * @Param [orgId]
     * @Return yb.ecp.fast.infra.infra.PageCommonVO<xcmg.device.service.vo.logistic.LogisticStatusDisplayBoardVO>
     */
    public PageCommonVO<LogisticStatusDisplayBoardVO> logisticStatusDisplayBoard(String orgId,Integer pageSize,Integer pageNum) {
        pageNum = pageNum == null ? 1 : pageNum;
        pageSize = pageSize == null ? 10 : pageSize;
        PageHelperPlus.startPage(pageNum, pageSize);
        List<LogisticStatusDisplayBoardVO> dataLst = logisticWaybillMapper.logisticStatusDisplayBoard(orgId);
        PageCommonVO<LogisticStatusDisplayBoardVO> result = new PageCommonVO<>();
        result.setPageInfo(new PageInfo(dataLst));
        result.setPageInfoList(dataLst);
        return result;
    }

    @Transactional
    public ActionResult synLogisticInfo(String wayBillId) throws Exception {
//        //查询物流单是否存在物流单号和物流商号
//        LogisticWaybillDO waybillDO = logisticWaybillMapper.selectByPrimaryKey(wayBillId);
//        if(waybillDO == null){
//            return ActionResultUtil.errorActionResult(ErrorCode.IllegalArument.getCode(),"未查询到物流运单");
//        }
//        String freightNo = waybillDO.getFreightNo();
//        if (StringUtils.isEmpty(freightNo)) {
//            return ActionResultUtil.errorActionResult(ErrorCode.IllegalArument.getCode(),"该物流单未维护物流单号，无法同步");
//        }
//        //如果单号以SF/sf开头的认为是顺丰，调用接口是需要加上手机号的后四位
//        if(freightNo.startsWith("SF") || freightNo.startsWith("sf")){
//            freightNo = freightNo.toUpperCase();
//            String receiverTel = waybillDO.getReceiverTel();
//            if(StringUtils.isEmpty(receiverTel) || receiverTel.length() != 11){
//                return ActionResultUtil.errorActionResult(ErrorCode.IllegalArument.getCode(),"顺丰快递需维护正确格式的收货人手机号");
//            }
//            freightNo = freightNo + ":" + receiverTel.substring(receiverTel.length() - 4);
//        }
//        String expressDesc = JsonUtil.objectToString(wdExpressClient.gxali(freightNo));
//        if(expressDesc==null || expressDesc.isEmpty()){
//            log.info("{} result expressDesc is null",wayBillId);
//            return ActionResultUtil.errorActionResult(ErrorCode.DeliveryReceiptNotExistExpressInfo);
//        }
//        //stringjson转对象
//        ExpressResultVO expressResultVO = new Gson().fromJson(expressDesc, new TypeToken<ExpressResultVO>() {
//        }.getType());
//        if(expressResultVO==null){
//            log.info("{} result expressResultVO is null",wayBillId);
//            return ActionResultUtil.errorActionResult(ErrorCode.DeliveryReceiptNotExistExpressInfo);
//        }
//        boolean success = expressResultVO.isSuccess();
//        if(!success){
//            log.info("{} result expressResultVO.isSuccess is false",wayBillId);
//            return ActionResultUtil.errorActionResult(ErrorCode.DeliveryReceiptNotExistExpressInfo);
//        }
//        String state = expressResultVO.getState();
//        if(StringUtils.isEmpty(state) || state.equals("0") || state.equals("-1")){
//            log.info("{} result state is null/0/-1",wayBillId);
//            return ActionResultUtil.errorActionResult(ErrorCode.DeliveryReceiptNotExistExpressInfo);
//        }
//        List<ExpressTracesVO> traces = expressResultVO.getTraces();
//        if (null == traces || traces.isEmpty()) {
//            log.info("{} result traces is empty",wayBillId);
//            return ActionResultUtil.errorActionResult(ErrorCode.DeliveryReceiptNotExistExpressInfo);
//        }
//
//        updateLogisticRecord(wayBillId,traces);
        return ActionResultUtil.successActionResult();
    }

    /**
     * @Des 调用第三方物流同步接口时更新物流单的物流信息
     * @Date 2021/5/28 16:43
     * @Author wangzhaoyu
     * @Param [wayBillId, traces]
     * @Return void
     */
    private void updateLogisticRecord(String wayBillId, List<ExpressTracesVO> traces) throws Exception {
        if(CollectionUtils.isEmpty(traces)){
            return ;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date currentTime = new Date();
        //把所有的自动的状态为运输中的物流信息都给删掉
        logisticNodeRecordMapper.deleteAutoDeliveryingLogisticRecord(wayBillId);
        //把同步到的物流信息落地
        List<LogisticNodeRecordDO> batchSaveDOs = new LinkedList<>();
        for(ExpressTracesVO trace : traces){
            Date acceptTime = null;
            try{
                String acceptTimeStr = trace.getAcceptTime();
                acceptTime = sdf.parse(acceptTimeStr);
            }catch (Exception e){
                log.error("同步物流信息转换日期异常",e);
            }
            LogisticNodeRecordDO saveDO = new LogisticNodeRecordDO();
            ActionResult<String> idResult = fastGenClient.textGuid();
            if (idResult == null || idResult.getCode() != 0) {
                throw new Exception("生成唯一标识失败");
            }
            saveDO.setId(idResult.getValue());
            saveDO.setRecordType(LogisticRecodeOperateTypeEnum.AUTO.getType());
            saveDO.setNodeType(LogisticNodeTypeEnum.TRANSPORTING.getType());
            saveDO.setCreateDate(currentTime);
            saveDO.setRecordTime(acceptTime);
            saveDO.setNodeInfo(trace.getAcceptStation());
            saveDO.setRecordUserId("00000");
            saveDO.setRecordUserName("系统自动");
            saveDO.setWayBillId(wayBillId);
            saveDO.setIsDel(0);
            batchSaveDOs.add(saveDO);
        }
        logisticNodeRecordMapper.batchInsertLogisticRecord(batchSaveDOs);
    }
}
